package com.mingke.common.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mingke.common.entity.SecretEntity;
import com.mingke.common.entity.UserEntity;
import com.mingke.common.mapper.UserDao;
import com.mingke.common.service.SecretService;
import com.mingke.common.service.UserService;
import com.mingke.common.transfer.LoginTO;
import com.mingke.common.transfer.RegisterTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
    @Autowired
    SecretService secretService;

    @Autowired
    @Qualifier("redisTemplate")
    RedisTemplate redisTemplate;

    @Override
    public String login(LoginTO loginTO) {
        if(loginTO.getUserLoginNumber() != null) {
            QueryWrapper<UserEntity> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("user_login_number", loginTO.getUserLoginNumber());
            List<UserEntity> lists = list(userQueryWrapper);
            if(lists.size() == 0) {
                return "用户不存在";
            }else if (lists.size() > 1){
                return "系统故障，用户号码重复";
            }else {
                BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
                Boolean loginResult = passwordEncoder.matches(loginTO.getPassword(), lists.get(0).getUserPassword());
                if(loginResult) {
                    UserEntity now = lists.get(0);
                    StpUtil.login(now.getUserUUID(), loginTO.getSource());
                    SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
                    //登录成功以后，需要在Redis里面去设置用户当前的登录状态
                    redisTemplate.opsForHash().put("user-online", now.getUserLoginNumber().toString(), true);
                    //登录成功以后，把Number和昵称的映射存储到redis
                    redisTemplate.opsForHash().put("user-nickname", now.getUserLoginNumber().toString(), now.getUserNickname());
                    return tokenInfo.tokenName+":"+tokenInfo.tokenValue;
                }else {
                    return "用户名密码不匹配";
                }
            }
        }
        return "Hello Login";
    }

    @Override
    public String register(RegisterTO registerTO) {
        UserEntity userEntity = new UserEntity();
        userEntity.setUserNickname(registerTO.getUsername());
        userEntity.setUserSex(registerTO.getSex());
        userEntity.setUserSchool(registerTO.getSchool());
        userEntity.setUserPassword(registerTO.getPassword());
        userEntity.setAddTime(new Date());
        userEntity.setUpdateTime(new Date());
        //生成全局唯一的uuid
        String uuid = IdUtil.simpleUUID();
        userEntity.setUserUUID(uuid);
        //生成用户的登录账号
        Integer userNumber = ThreadLocalRandom.current().nextInt(1000, 10000);
        userEntity.setUserLoginNumber(userNumber);
        //用户密码明文的加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        userEntity.setUserPassword(passwordEncoder.encode(registerTO.getPassword()));
        save(userEntity);
        //用户密码的明文，再存储一遍
        secretService.save(new SecretEntity(uuid, registerTO.getPassword()));
        return userNumber.toString();
    }

    @Override
    public String loginout(Integer loginNumber) {
        //退出登录
        StpUtil.logout();
        //更新redis里面的信息
        if((Boolean) redisTemplate.opsForHash().get("user-online", loginNumber)) {
            redisTemplate.opsForHash().put("user-online", loginNumber, false);
        }
        return "ok";
    }
}